아키텍처 분석
폴더 구조에 대해 알아보겠습니다 !ㅅ!
📂components
components라는건 재사용이 가능한 작은 부품을 의미한다.
component의 어원이 갑자기 궁금해서 찾아봤더니
com(함께) + ponere(놓다) 라는 라틴어에서 왔다고 한다.
그래서 큰 걸 이루는 작은 조각들이라는 뜻을 갖고 있다고.
원본 레포의 components 파일 구조를 보기 전에,
페이지별 UI를 참고해서 직접 컴포넌트들을 아래처럼 나눠봤다.
(에러나 로딩 상태는 제외하고 정리함)
🦭 내가 짠 구조
- layout
- AppHeader
- AppNavgations
- AppFooter
- banner
- HomeBanner
- ArticleBanner
- ProfileBanner
- tag
- TagItem
- TagList
- tab
- TabItem
- TabList
- button
- SolidButton
- OutlineButton
- IconLabelButton
- IconButton
- user
- UserIcon
- UserItem
- article
- PreviewArticleCard
- PreviewArticleList
- DetailArticleCard
- comment
- CommentCard
- CommentList
- input
- InputForm
- InputArticle
- InputComment
🦫 원본 레포 구조
- article
- ArticleActions
- ArticleList
- ArticleMeta
- ArticlePreview
- comment
- Comment
- CommentInput
- CommentList
- DeleteButton
- common
- CustomImage
- CustomLink
- ErrorMessage
- Footer
- Layout
- ListErrors
- LoadingSpinner
- Maybe
- Navbar
- NavLink
- Pagination
- editor
- TagInput
- home
- Banner
- MainView
- TabList
- Tags
- profile
- EditProfileButton
- FollowUserButton
- LoginForm
- ProfileTab
- RegisterForm
- SettingsForm
오.. 뭔가 차이가 되게 많은 것 같다.
나는 UI 요소 중심으로 컴포넌트 구조를 나눈 반면,
원본 레포는 특정 기능이나 API 엔드포인트를 중심으로 나눈 구조 같았다.
아키텍처 패턴 이름들을 잘 몰라서
클로드한테 내가 짠 거랑 원본 레포가 각각 어떤 패턴인지 물어봤는데,
나는 Atomic Design Pattern과 유사하고
원본 레포는 Domain Driven Design과 유사하다고 한다.
아토믹 디자인 패턴은 저번 프로젝트 때 들어봐서 아는데,
DDD는 또 뭐지? 하고 찾아보니까
한마디로 기능별로 도메인 중심으로 구조화한 패턴이라고 한다.
아토믹과 DDD의 장단점은 다음과 같다.
구분 | Atomic Design | DDD (Domain Driven Design) |
---|---|---|
장점 | • 재사용성 극대화 • 일관된 디자인 시스템 구축 | • 응집도는 높고 결합도는 낮음 • 기능 단위 배포 및 관리 용이 |
단점 | • 비즈니스 로직이 분산될 수 있음 • 특정 기능 개발 시 여러 폴더 탐색 필요 • 도메인 응집도 낮음 • 상태 관리 복잡 가능성 | • UI 컴포넌트 재사용성 낮을 수 있음 • 공통 UI 요소 중복 구현 가능성 • 디자인 시스템 유지 어려움 • UI 일관성 유지 어려울 수 있음 |
장단점이 너무 확연하게
아토믹은 디자인 쪽에 치우쳐져 있고,
DDD는 말그대로 도메인 쪽에 특화되어 있는 설계 방식인 것 같다고 느껴졌다.
해당 프로젝트는 API와의 통신이 필요하니
서버와의 상태관리를 위해 도메인별로 분리를 하는게 좋다고 생각했다.
근데 아토믹의 디자인 장점은 가져가면서 도메인의 장점은 결합한 패턴은 없나? 하고 찾아봤는데,
이 둘을 같이 활용하는게 하이브리드 아키텍처 패턴이다.
그래서 button 컴포넌트는 공통된 ui가 많으니 profile 같은 특정 도메인 폴더에 넣기보단,
ui쪽에서 따로 관리하는게 더 좋지 않을까라는 생각이 들었다.
결론적으로
features에는 특정 도메인 관련 컴포넌트들을 넣고, (=DDD)
shared에 ui와 components 디렉토리를 만드는 식으로 폴더 구조를 수정했다.
공통된 디자인 관련은 다 ui로 빼고싶었지만,
아직 코드를 제대로 안 읽어봐서 이 과정은 좀 추후에 해야겠다고 생각하고 폴더만 미리 만들어뒀다.
결론적으로 내가 리팩토링한 폴더 구조는 다음과 같다.
🦦 리팩토링 구조
참고로, Next.js랑 가장 어울리는 아키텍처 패턴은 Feature-Sliced Design (FSD)라고 한다.
이건 또 뭔가 싶어서 찾아봤는데, 말 그대로 기능(Feature)을 중심으로 폴더를 나누는거다.
DDD가 도메인 중심이라면,
FSD는 UI와 유저 흐름 중심으로 잘게 쪼개는 구조라고 보면 된다.
이가 next.js와 잘 어울리는 이유는 페이지 단위로 라우팅 되는 특성과 잘 어울리기 때문이라고..
📂pages
React를 사용할 시 React Router와 같은 라이브러리를 활용해서
라우팅을 직접 설정해줘야 했다.
하지만 Next.js는 파일 구조 자체가 곧 라우팅 설정이다.
즉, 별도의 라우터 설정 없이도 폴더와 파일명만으로 URL 구조가 자동으로 결정된다.
RealWorld는 api 명세를 따라 프로젝트가 동일하게 관리되기 때문에
크게 article, editor, profile, user, home(root) 총 5가지의 경로가 존재한다.
- article
- [pid]
- editor
- [pid]
- new
- profile
- [pid]
- user
- login
- register
- settings
article과 editor, profile의 경우에는 []
대괄호로 감싸져 있는데
이는 next.js의 동적 라우팅을 의미하며,
하나의 컴포넌트로 무수히 많은 URL 패턴을 처리할 수 있게 해준다.
나머지는 정적 경로로 고정된 URL을 가진다.
루트에는 index와 _app
, _document
가 있다.
- index
- 해당 디렉토리의 기본 페이지(루트, 홈)를 의미한다.
_app
- 모든 페이지의 최상위 컴포넌트이다.
항상 페이지가 렌더링되기 전에 먼저 실행되며,
전역 CSS, 상태 관리, 공통 레이아웃, 인증 처리 등을 담당한다.
- 모든 페이지의 최상위 컴포넌트이다.
_document
- HTML 문서의 구조 자체를 커스터마이징하는 파일이다.
<html>
,<head>
,<body>
태그를 직접 제어할 수 있으며,
메타 태그, 폰트 로딩, 서드파티 스크립트 삽입 등 HTML 문서 레벨의 설정을 담당한다.
서버 사이드에서만 실행된다.
- HTML 문서의 구조 자체를 커스터마이징하는 파일이다.
📂lib
마치 엔진룸(?)처럼 로직과 유틸리티들을 모아두는 디렉토리다.
- api
- article
- comment
- tag
- user
- context
- index
- PageContext
- PageCountContext
- hooks
- useMounted
- useSessionStorage
- useViewport
- types
- articleType
- commentType
- tagType
- utils
- calculatePagination
- checkLogin
- constant
- editorReducer
- fetcher
- getQuery
- handleBrokenImage
- storage
- api/
- 백엔드 API와 통신하는 함수들의 집합이다.
article
,comment
,tag
,user
로 나뉘어 있는데,
이는 앞서 pages 구조와 동일하게 RealWorld Api 명세의 ==엔드포인트 구조를
그대로 반영==한 것이다.
- 백엔드 API와 통신하는 함수들의 집합이다.
- context/
- React Context API를 활용한 전역 상태 관리.
PageContext
와PageCountContext
로 페이지네이션 관련 상태들을 관리하는 것 같다.
- React Context API를 활용한 전역 상태 관리.
- hooks/
- 커스텀 훅들의 모음.
- types/
- TypeScript 타입 정의들.
- utils/
- 순수 함수들과 헬퍼 함수들.
맺음말
번외
- Q. app or pages 디렉토리 안에 components를 두는 것과 밖에 두는 것의 차이점이 뭘까?
- 최근 버전들로 만들어진 RealWorld 프로젝트를 보는데,
어떤분은 components 폴더를 루트에 두고,
어떤분은 라우터 디렉토리 안에 둬서
이에 어떤 차이점이 있는지 궁금해졌다. - 이 질문엔 명확한 정답은 없으며 그냥 차이점만 있을 뿐이다.
최신 버전의 next.js는page.js
나layout.js
와 같은 특정 파일만 라우팅 되기 때문에
라우터 폴더 안에 다른 컴포넌트 폴더를 둬도 라우팅이 되지 않지만,
구버전(12 이하)의 경우엔 pages 디렉토리 안에 있는 모든 파일들이
자동으로 라우팅 되기 때문에 루트에 따로 빼줘야 됐다.
그냥 버전 차이로 인한 해프닝(?)인걸루
- 최근 버전들로 만들어진 RealWorld 프로젝트를 보는데,
느낀점
사실 나는 아키텍처나 디자인 패턴을 그리 좋아하지 않는다.
왜냐면 종류가 너무 다양하고... 관련 설명 글을 읽으면 너무 복잡해보이기 때문이다 ㅋㅋㅠ
근데 이건 항상 내가 0부터 프로젝트를 만들어왔기 때문이고,
직장이든 팀플이든 어딜 중간에 들어가면
남이 짜놓은 코드를 먼저 보게 될텐데
디렉토리 구조가 중구난방하게 흩어져있으면
이 컴포넌트 코드는 어딨지 하면서 찾다가 밤낮을 지새울거다 ㄷㄷ
이번에 프로젝트 초기 세팅할 때도
api 관련은 바로 utils 폴더에 있어서 찾기 쉬웠었다.
일단 오늘은 여기서 끗..